from django.forms import ModelForm, ChoiceField
from django.contrib.gis.db import models
from django.contrib.flatpages.models import FlatPage
from django.contrib.auth.models import User, Group
from django.core.files.storage import FileSystemStorage
from django.core.cache import cache
from django.db import connection
from django.core.exceptions import ValidationError

import datetime,os,subprocess,zipfile,simplejson,re
import settings
from util import *

file_location = FileSystemStorage(location=settings.GROUP_IMAGES)

class media_type(models.Model):
    name = models.CharField(max_length=50)

    def __unicode__(self):
        return unicode('%s' % self.name)

    class Meta:
        verbose_name = ('CE Atlas Media Type')
        verbose_name_plural = ('Media Types')

class theme(models.Model):
    title = models.CharField(max_length=100)
    description = models.TextField(blank=True)
    sub_themes = models.ManyToManyField("self",symmetrical=False,blank=True)
    date_added = models.DateField('Date Added', default=datetime.datetime.now().strftime("%Y-%m-%d"))
    date_start = models.DateField('Start Date', null=True, blank=True)
    date_end = models.DateField('End Date', null=True, blank=True)
    groups = models.ManyToManyField(Group)
    order = models.PositiveSmallIntegerField('Display Order', default=999)
    
    def __unicode__(self):
        return unicode('%s' % self.title)

    class Meta:
        verbose_name = ('CE Atlas Theme')
        verbose_name_plural = ('Themes')
        ordering = ['order']


class UserUploadedShapes(models.Model):
    geoms = models.GeometryCollectionField()
    attributes = models.TextField(blank=True)
    style = models.TextField(default='{}')
    last_modified_date = models.DateTimeField(auto_now=True,auto_now_add=True,default=datetime.datetime.now())

    def delete(self, *args, **kwargs):
        cache.delete('user_uploaded_shapes')
        super(UserUploadedShapes, self).delete(*args, **kwargs)

    def save(self, *args, **kwargs):
        cache.delete('user_uploaded_shapes')
        return super(UserUploadedShapes, self).save(*args, **kwargs)

    def GetType(self):
        if not geoms.empty:
            return 'Empty'
        return geoms[0].geom_type
    
    def __unicode__(self):
        return unicode('id: %s' % self.id)
    
    class Meta:
        verbose_name = ('User Uploaded Shape')
        verbose_name_plural = ('User Uploaded Shapes')
        get_latest_by = ('last_modified_date')


class media(models.Model):
    title = models.CharField(max_length=50)
    type = models.ForeignKey(media_type)
    content = models.TextField()
    source = models.CharField(max_length=100)
    latitude = models.FloatField(blank=True,null=True)
    longitude = models.FloatField(blank=True,null=True)
    date_added = models.DateField('Date Added', default=datetime.datetime.now().strftime("%Y-%m-%d"))
    date_start = models.DateField('Start Date', null=True, blank=True)
    date_end = models.DateField('End Date', null=True, blank=True)
    themes = models.ManyToManyField(theme)
    remote_address = models.CharField(max_length=15,blank=True)
    owner = models.ForeignKey(User, blank=True, null=True)
    user_shapes = models.ForeignKey(UserUploadedShapes, blank=True, null=True)
    
    def __unicode__(self):
        return unicode('%s' % self.title)

    class Meta:
        verbose_name = ('CE Atlas Media')
        verbose_name_plural = ('Media')

class wms_format(models.Model):
    format = models.CharField(max_length=30)

    def __unicode__(self):
        return unicode('%s' % self.format)

    class Meta:
        verbose_name = ('WMS Format')
        verbose_name_plural = ('WMS Formats')

class wms_layer(models.Model):   
     
    def delete(self, *args, **kwargs):
        cursor = connection.cursor()
        #drop the table with old layer name if exists
        table_name = 'user_shape_%s' % self.layers
        cursor.execute("select * from information_schema.tables where table_name=%s", (table_name,))
        if cursor.rowcount: #delete the old table if exists.
            cursor.execute('DROP TABLE %s ;' % table_name)
        # garbage collection: remove record in geometry_columns
        cursor.execute("delete from geometry_columns where f_table_name=%s", (table_name,))
        mapserverdir = os.path.join(settings.ROOT, 'mapserver')
        generate_map_file()
        return super(wms_layer, self).delete(*args, **kwargs)
    
    def user_shape_location (instance, filename):
        if not os.path.exists('/tmp/user_shape_uploads_atlas'):
            os.mkdir('/tmp/user_shape_uploads_atlas')
        upload_dir = os.path.join(settings.MEDIA_ROOT, 'uploads')
        os.system('rm -Rf %s' % upload_dir)
        os.system('ln -s /tmp/user_shape_uploads_atlas/ %s' % (settings.MEDIA_ROOT + '/uploads'))
        filepath = os.path.join(upload_dir, filename)
        os.system('rm -Rf %s' % filepath)
        return filepath
   
    title = models.CharField(max_length=100)
    description = models.TextField(blank=True)
    order = models.IntegerField(null=True)
    url = models.CharField(max_length=1024, default='/cgi-bin/ce_atlas.cgi?')
    layers = models.TextField(blank=True, default='undefined')
    style = models.TextField(default='{"COLOR":"#ee9900","OUTLINECOLOR":"#ee9900","WIDTH":"1"}', blank=True, null=True)
    visibility = models.BooleanField(default=True)
    opacity = models.FloatField(default=1)
    format = models.ForeignKey(wms_format,default=2, blank=True)
    date_added = models.DateField('Date Added', default=datetime.datetime.now().strftime("%Y-%m-%d"))
    date_start = models.DateField('Start Date', null=True, blank=True)
    date_end = models.DateField('End Date', null=True, blank=True)
    themes = models.ManyToManyField(theme)
    show_legend = models.BooleanField(default=True)
    tag = models.CharField(max_length=255, blank=True, help_text='comma delimited, flags used internally.')
    user_file = models.FileField(upload_to=user_shape_location,null=True, blank=True)
    user_file_type = models.CharField(max_length=10, blank=True, null=True)
    label_field_name = models.CharField(max_length=100, blank=True, null=True)
    label_style = models.TextField(default='{"COLOR":"#ffffff","SIZE":"9","FONT":"calibri"}', blank=True, null=True)
    
    def __unicode__(self):
        return unicode("%s" % (self.title))

    class Meta:
        verbose_name = 'WMS Layer'
        verbose_name_plural = 'WMS Layers'

class wms_layer_form(ModelForm):
    label_field_name = ChoiceField(required=False)

    def __init__(self, *args, **kwargs):
        super(wms_layer_form, self).__init__(*args, **kwargs)
        self.fields['label_field_name'].choices = [('','')]
        cursor = connection.cursor()
        table_name = 'user_shape_%s' % self.instance.layers
        cursor.execute("select column_name from information_schema.columns where table_name=%s", (table_name,))
        if cursor.rowcount: #delete the old table if exists.
            column_names = cursor.fetchall()
            for column_name in column_names:
                column_name = str(column_name[0])
                if column_name != 'the_geom':
                    self.fields['label_field_name'].choices.append((column_name, column_name))
    
    class Meta:
        model = wms_layer
   
    def save(self, *args, **kwargs):
        cursor = connection.cursor()
        if self.cleaned_data['layers'].strip() == 'undefined':
        #if layers are not specified, then set it to be the title with spaces removed.
            self.cleaned_data['layers'] = re.sub(r'[^a-zA-Z\d]', '', self.cleaned_data['title']).lower()
       
        if 'user_file' in self.changed_data: #a new shape file is uploaded

            if 'layers' in self.changed_data:
                #drop the table with old layer name if exists
                table_name = 'user_shape_%s' % self.instance.layers
                cursor.execute("select * from information_schema.tables where table_name=%s", (table_name,))
                if cursor.rowcount: #delete the old table if exists.
                    cursor.execute('DROP TABLE %s ;' % table_name)
        
            try:
                zfile = zipfile.ZipFile(self.cleaned_data['user_file'], 'r')
            except:
                raise ValidationError("Invalid Zip File")
            corr_extensions = ['dbf', 'prj', 'shp', 'shx']
            extensions = [file_extension(i.lower()) for i in zfile.namelist()]
            good_zip_file = True
            shp_filename = ''
            for ce in corr_extensions:
                if ce not in extensions:
                    good_zip_file = False
                    break
            if not good_zip_file:
                raise ValidationError("Invalid Shape File")
            for name in zfile.namelist():
                data = zfile.read(name)
                fname = re.sub(r'[^a-zA-Z\d\.]', '', name.lower())
                path = os.path.join('/tmp/', fname)
                if file_extension(fname) == 'shp':
                    shp_filename = fname
                fd = open(path, 'wb')
                fd.write(data)
                fd.close()
                os.chmod(path, 0777)
        
            #drop the table with new layer name if exists
            table_name = 'user_shape_%s' % self.cleaned_data['layers']
            cursor.execute("select * from information_schema.tables where table_name=%s", (table_name,))
            if cursor.rowcount: #delete the old table if exists.
                cursor.execute('DROP TABLE %s ;' % table_name)

            p = subprocess.Popen(r"shp2pgsql -s 4326 -W LATIN1 -I %s user_shape_%s" % (os.path.join('/tmp', shp_filename), self.cleaned_data['layers']), shell=True, stderr = subprocess.PIPE, stdout = subprocess.PIPE)
            sql = p.stdout.read()
            cursor.execute(sql)
            
            p.stderr.readline()
            typestr = p.stderr.readline()
            user_file_type = 'POINT'
            if 'POLYGON' in typestr:
                user_file_type = 'POLYGON'
            elif 'LINE' in typestr:
                user_file_type = 'LINE'
            self.cleaned_data['user_file_type'] = user_file_type
            
        elif 'layers' in self.changed_data:
            #rename the table to the new layer name if exists
            table_name = 'user_shape_%s' % self.instance.layers
            new_table_name = 'user_shape_%s' % self.cleaned_data['layers']
            cursor.execute("select * from information_schema.tables where table_name=%s", (table_name,))
            if cursor.rowcount: 
                cursor.execute('ALTER TABLE %s RENAME TO %s ;' % (table_name, new_table_name))
      
        result = super(wms_layer_form, self).save(*args, **kwargs)
        result.layers = self.cleaned_data['layers']
        result.user_file_type = self.cleaned_data['user_file_type']
        generate_map_file(result)
        return result

   


class wfs_layer(models.Model):
    title = models.CharField(max_length=100)
    description = models.TextField(blank=True)
    order = models.IntegerField(null=True)
    url = models.CharField(max_length=1024, default='/cgi-bin/ce_atlas.cgi?')
    layers = models.TextField()
    style = models.TextField(default='{fillColor: "", fillOpacity: 0.6, strokeColor: "", strokeOpacity: "", strokeWidth: "", strokeLinecap: "", strokeDashstyle: "", pointRadius: "", pointerEvents: "", cursor: "", externalGraphic: "", graphicWidth: "", graphicHeight: "", graphicOpacity: "", graphicXOffset: "", graphicYOffset: "", graphicName: "", display: ""}')
    visibility = models.BooleanField(default=True)
    date_added = models.DateField('Date Added', default=datetime.datetime.now().strftime("%Y-%m-%d"))
    date_start = models.DateField('Start Date', null=True, blank=True)
    date_end = models.DateField('End Date', null=True, blank=True)
    themes = models.ManyToManyField(theme)
    cluster = models.BooleanField(default=False)
    tag = models.CharField(max_length=255, blank=True, help_text='comma delimited, flags used internally.' )
    def __unicode__(self):
        return unicode("%s" % (self.title))

    class Meta:
        verbose_name = 'WFS Layer'
        verbose_name_plural = 'WFS Layers'

class place(models.Model):   
    html_id = models.CharField(max_length=100)
    title = models.CharField(max_length=100)
    sub_places = models.ManyToManyField("self",symmetrical=False,blank=True)
    western_longitude = models.FloatField(blank=False,null=False)
    southern_latitude = models.FloatField(blank=False,null=False)
    eastern_longitude = models.FloatField(blank=False,null=False)
    northern_latitude = models.FloatField(blank=False,null=False)
    image_url = models.CharField(max_length=1024, null=True, blank=True)
    groups = models.ManyToManyField(Group)
    def __unicode__(self):
        return unicode("%s" % (self.title))

    class Meta:
        verbose_name = 'Place'
        verbose_name_plural = 'Places'

class group_attribute(models.Model):
    title = models.CharField(max_length=100,blank=True,null=True)
    group = models.OneToOneField(Group)
    domain = models.CharField(max_length=100)
    hide_timeline_default = models.BooleanField(default=False)
    location_western_longitude = models.FloatField(blank=False,null=False)
    location_southern_latitude = models.FloatField(blank=False,null=False)
    location_eastern_longitude = models.FloatField(blank=False,null=False)
    location_northern_latitude = models.FloatField(blank=False,null=False)
    logo_image = models.ImageField(storage=file_location, upload_to=settings.GROUP_IMAGES, blank=True, null=True)
    show_header_animation = models.BooleanField(default=False)
    show_logo_and_copyright = models.BooleanField('Show Ecotrust Logo and Copyright', default=True)
    header_animation_image1 = models.ImageField(storage=file_location, upload_to=settings.GROUP_IMAGES, blank=True, null=True)
    header_animation_image2 = models.ImageField(storage=file_location, upload_to=settings.GROUP_IMAGES, blank=True, null=True)
    header_animation_image_url = models.CharField(max_length=1024, blank=True, null=True)
    online_help_url = models.CharField(max_length=1024, blank=True, null=True,default="http://nativemaps.org/node/3718")
    default_theme = models.ForeignKey(theme, blank=True, null=True)
    intro = models.TextField(blank=True, null=True)
    tour_step1_title = models.CharField('Tour Step 1 - Title', max_length=50, blank=True, null=True)
    tour_step1_content = models.TextField('Tour Step 1 - Content', blank=True, null=True)
    tour_step2_title = models.CharField('Tour Step 2 - Title', max_length=50, blank=True, null=True)
    tour_step2_content = models.TextField('Tour Step 2 - Content', blank=True, null=True)
    tour_step3_title = models.CharField('Tour Step 3 - Title', max_length=50, blank=True, null=True)
    tour_step3_content = models.TextField('Tour Step 3 - Content', blank=True, null=True)
    tour_step4_title = models.CharField('Tour Step 4 - Title', max_length=50, blank=True, null=True)
    tour_step4_content = models.TextField('Tour Step 4 - Content', blank=True, null=True)
    tour_step5_title = models.CharField('Tour Step 5 - Title', max_length=50, blank=True, null=True)
    tour_step5_content = models.TextField('Tour Step 5 - Content', blank=True, null=True)
    about = models.TextField('Tour Step 6', blank=True, null=True)
    about_flat_page = models.ForeignKey(FlatPage, blank=True, null=True)
    header_background_color = models.CharField(max_length=20,blank=True,null=True,default="#d7ce81")
    header_link_color = models.CharField(max_length=20,blank=True,null=True,default="#D3181C")
    contact_us_email = models.CharField(max_length=30,blank=True,null=True,default="livingatlas@ecotrust.ca")
    google_analytics_id = models.CharField('Google Analytics Tracking ID',max_length=20,blank=True, null=True)
    
    def __unicode__(self):
        return unicode('%s attribute' % self.group)

    class Meta:
        verbose_name = ('Group Attribute')
        verbose_name_plural = ('Group Attributes')
       



